"""
简单的web服务端程序
B/S
"""
from socket import *
from select import select


# 处理浏览器请求
class HandleRequest:
    def __init__(self, html):
        self.html = html  # ./static

    # 组织响应 ，发送响应
    def _send_response(self, connfd, info):
        if info == '/':
            filename = self.html + "/index.html"
        else:
            filename = self.html + info

        # 直接尝试打开
        try:
            file = open(filename, 'rb')
        except:
            # 文件不存在
            response = "HTTP/1.1 404 Not Found\r\n"
            response += "Content-Type:text/html\r\n"
            response += "\r\n"
            with open(self.html + "/404.html") as f:
                response += f.read()
            response = response.encode()
        else:
            # 文件存在
            response = "HTTP/1.1 200 OK\r\n"
            response += "Content-Type:text/html\r\n"
            response += "\r\n"
            response = response.encode() + file.read()
        finally:
            connfd.send(response)

    def handle(self, connfd):
        # 接收HTTP请求
        request = connfd.recv(1024).decode()
        if not request:
            return
        # 获取请求内容
        info = request.split(' ')[1]
        print("请求内容:", info)
        # 发送响应
        self._send_response(connfd, info)


class WebServer:
    def __init__(self, *, host="0.0.0.0", port=0, html=None):
        self.host = host
        self.port = port
        self.address = (host, port)
        self.html = html
        self.rlist = []
        self.handle = HandleRequest(self.html)  # 实例化对象
        self.sock = self._create_socket()

    def _create_socket(self):
        sock = socket()
        sock.bind(self.address)
        sock.setblocking(False)
        return sock

    # 处理客户端连接
    def _connect_client(self):
        connfd, addr = self.sock.accept()
        connfd.setblocking(False)
        self.rlist.append(connfd)  # 增加关注对象

    def start(self):
        self.sock.listen(5)
        print("Listen the port %d" % self.port)
        self.rlist.append(self.sock)
        # 循环监控
        while True:
            rs, ws, xs = select(self.rlist, [], [])
            for r in rs:
                if r is self.sock:
                    self._connect_client()  # 连接客户端
                else:
                    # 处理浏览器请求
                    try:
                        self.handle.handle(r)
                    except:
                        pass
                    finally:
                        self.rlist.remove(r)
                        r.close()


if __name__ == '__main__':
    # 需要用户决定的通过参数传入
    httpd = WebServer(host="0.0.0.0", port=8000, html="./static")
    httpd.start()  # 启动服务
